package br.com.viamais.util;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * Utility Hibernate Class to manager the session.
 * <ul>
 * <li>Initialize a new static session factory.</li>
 * <li>Open hibernate sessions.</li>
 * <li>Associate local threads to sessions.</li>
 * <li>Close associate sessions.</li>
 * </ul>
 * TODO: Logger
 * 
 */
public final class HibernateUtil {
	/**
	 * Hibernate configuration.
	 */
	private static final String HIBERNATE_CFG = "/br/com/viamais/resources/hibernate.cfg.xml";
	/**
	 * SessionFactory.
	 */
	private static SessionFactory sessionFactory;
	/**
	 * Type safe local thread.
	 */
	private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>();
	/**
	 * Session
	 */
	private static Session session;

	/**
	 * Create a new sessionFactory.
	 */
	public static void initialize() {
		try {
			System.out.println(">>> HIBERNATE: initializing...");
			sessionFactory = new Configuration().configure(HIBERNATE_CFG)
					.buildSessionFactory();
			if(sessionFactory != null) {
				System.out.println(">>> HIBERNATE: initialized sucessful!");
			} else {
				throw new Throwable();
			}
		} catch (Throwable e) {
			System.out.println(">>> HIBERNATE: initialization error!");
			e.printStackTrace();
		}
	}

	/**
	 * Re-initialize a current session.
	 */
	public static void reinitialize() {
		closeSession();
		initialize();
		getSession();
	}

	/**
	 * Clear the current Session
	 */
	public static void clearSession() {
		System.out.println(">>> HIBERNATE: clearing session...");
		Session s = HibernateUtil.getSession();
		System.out.println(">>> HIBERNATE: session cleared!");
		s.clear();
	}

	/**
	 * Return a current session or open a new session associate with
	 * ThreadLocal.
	 * 
	 * @return Session: hibernate session.
	 */
	public static Session getSession() {
		if (sessionFactory == null) {
			initialize();
		}
		session = (Session) threadSession.get();
		if (session == null) {
			System.out.println(">>> HIBERNATE: openning session...");
			try {
				session = sessionFactory.openSession();
				System.out.println(">>> HIBERNATE: session openned!");
				threadSession.set(session);
			} catch (HibernateException e) {
				System.out.println(">>> HIBERNATE: failed...");
			}
		}
		return session;
	}

	/**
	 * Close the ThreadLocal associate session.
	 */
	public static void closeSession() {
		Session s = (Session) threadSession.get();
		threadSession.set(null);
		if (s != null && s.isOpen()) {
			System.out.println(">>> HIBERNATE: closing session...");
			s.close();
			System.out.println(">>> HIBERNATE: session closed!");
		}
	}

}
